package com.tom.hook;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Added by Tom on 2024/07/09.
 */
public class HookStartActivityUtil {
    private static final String TAG = "HookStartActivityUtil";
    private Context mContext;
    private Class<?> mProxyClass; // 用来过安检的类。已经注册过的类。
    private final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";

    public HookStartActivityUtil(Context context, Class<?> proxyClass) {
        this.mContext = context.getApplicationContext(); // 以防内存泄漏
        this.mProxyClass = proxyClass;
    }

    // 拦截startActivity()
    public void hookStartActivity() throws Exception {
        Object singleTon = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            @SuppressLint("PrivateApi")
            Class<?> activityManagerClass = Class.forName("android.app.ActivityTaskManager");
            Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityTaskManagerSingleton");
            iActivityManagerSingletonField.setAccessible(true);
            singleTon = iActivityManagerSingletonField.get(null);
            Log.d(TAG, "singleTon:" + singleTon.toString());
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            /*
             * android 26或以上版本的API是一样的
             */
            Class<?> activityManagerClass = Class.forName("android.app.ActivityManager");
            Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("IActivityManagerSingleton");
            iActivityManagerSingletonField.setAccessible(true);
            singleTon = iActivityManagerSingletonField.get(null);
        } else {
            /*
             *  android 26或以下版本的API是一个系列
             */
            // 2.1 获取ActivityManagerNative里面的IActivityManagerSingleton( 旧版本gDefault)
            Class<?> activityManagerClass = Class.forName("android.app.ActivityManagerNative");
            // 2.2 获取属性gDefault: IActivityTaskManagerSingleton(旧版本 gDefault)属性。
            Field iActivityManagerSingletonField = activityManagerClass.getDeclaredField("gDefault");
            iActivityManagerSingletonField.setAccessible(true);
            singleTon = iActivityManagerSingletonField.get(null); // 静态变量，传null
        }

        // 2.3 通过gDefault的mInstance属性
        // 而实际上AMS在单例Singleton中
        Class<?> singletonClazz = Class.forName("android.util.Singleton");
        Field mInstanceField = singletonClazz.getDeclaredField("mInstance"); // 真正执行的类，是Singleton的mInstance
        mInstanceField.setAccessible(true);
        Object iamInstance = mInstanceField.get(singleTon); // AMS，真正的调用者。
        if (iamInstance == null) Log.e(TAG, "iamInstance is null!!!");

        Class<?> iActivityManagerClass;
        // 因为生成的接口类变了，所以这里我们需要根据版本来代理不同的接口class
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // android10+ 代理IActivityTaskManager
            iActivityManagerClass = Class.forName("android.app.IActivityTaskManager");
        } else {
            // android10- 代理IActivityManager
            iActivityManagerClass = Class.forName("android.app.IActivityManager");
        }
        iamInstance = Proxy.newProxyInstance(HookStartActivityUtil.class.getClassLoader(),
                new Class[]{iActivityManagerClass},
                // InvocationHandler 执行者，
                new StartActivityInvocationHandler(iamInstance));
        // 4. 重新设定进去, 重新设定为我们的代理。
        mInstanceField.set(singleTon, iamInstance);
    }

    // 动态代理 InvocationHandler
    private class StartActivityInvocationHandler implements InvocationHandler {
        // 方法真正的执行者mObject。高版本API中，拿到的这个值为null。可使用腾讯的Shadow 插件化框架。
        private Object mObject;
        public StartActivityInvocationHandler(Object object) {
            this.mObject = object;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.e(TAG, "method: " + method.getName());
            // **** 2.3.1 替换intent，过AndroidManifest.xml 的检测
            if (method.getName().equals("startActivity")) { // 只需要处理startActivity
                // 1.获取原来intent替换，最后启动的时候再替换回来。intent 在第二个位置
                Intent originIntent = (Intent) args[2];
                // 2.使用安全的intent替换。去安检。
                Intent safeIntent = new Intent(mContext, mProxyClass);
                args[2] = safeIntent; // 替换Intent
                // 3.绑定原来的(缓存原来的 originIntent)
                safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);

                // 4.------兼容AppCompatActivity 报错的问题。------
                Class<?> forName = Class.forName("android.app.ActivityThread");
                Field field = forName.getDeclaredField("sCurrentActivityThread");
                field.setAccessible(true);
                Object activityThread = field.get(null);
                // 自己执行一次方法，创建 PackageManager 对象；系统再次获取的时候，就直接拿缓存。
                Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
                Object iPackageManager = getPackageManager.invoke(activityThread);

                // 动态代理
                PackageManagerHandler handler = new PackageManagerHandler(iPackageManager);
                Class<?> iPackageManagerIntercept = Class.forName("android.content.pm.IPackageManager");
                Object proxy2 = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                        new Class<?>[]{iPackageManagerIntercept}, handler);
                // 获取 sPackageManager 属性
                Field iPackageManagerField = activityThread.getClass().getDeclaredField("sPackageManager");
                iPackageManagerField.setAccessible(true);
                iPackageManagerField.set(activityThread, proxy2);
            }
            return method.invoke(mObject, args);
        }
    }

    // 4.2 兼容AppCompatActivity 报错的问题
    //--------动态代理，hook iPackageManager 的getActivityInfo() ---------------
    class PackageManagerHandler implements InvocationHandler {
        private Object mActivityManagerObject;
        public  PackageManagerHandler(Object iActivityManagerObject) {
            this.mActivityManagerObject = iActivityManagerObject;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().equals("getActivityInfo")){
                ComponentName componentName = new ComponentName(mContext, mProxyClass);
                args[0] = componentName; // 名字变成自己的componentName
            }
            // 再次扫描，就不会报错
            return method.invoke(mActivityManagerObject, args);
        }
    }

    // hook handler（ActivityManager.mH）
    public void hookLaunchActivity() throws Exception {
        // 2.4.1 获取 ActivityThread 实例；
        Class<?> atClass = Class.forName("android.app.ActivityThread");
        Field scatField = atClass.getField("sCurrentActivityThread"); // 拿到属性
        scatField.setAccessible(true);
        Object sCurrentActivityThread = scatField.get(null); // 静态的，传入null

        // 2.4.2 获取  ActivityThread中的 mH。
        Field mHField = atClass.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler mHandler = (Handler) mHField.get(sCurrentActivityThread);

        // 2.4.3 hook  handleLaunchActivity.
        // 给Handler 设置Callback
        Class<?> handlerClass = Class.forName("android.os.Handler");
        Field mCallback = handlerClass.getDeclaredField("mCallback");
        mCallback.setAccessible(true);
        mCallback.set(mHandler, new HandlerCallback()); // 调用HandlerCallback.handleMessage()
    }

    @SuppressLint("NewApi")
    private class HandlerCallback implements Handler.Callback {
        @Override
        public boolean handleMessage(Message msg) {
            Log.e(TAG, "HandlerCallback: handleMessage ！" );
            // 每发一个消息，都会走handleMessage 方法一次。
            // public static final int LAUNCH_ACTIVITY = 100; // ActivityThread.java
            if (msg.what == 100) {
                handleLaunchActivity(msg); // 还原intent
            }
            return false; // 必须返回false，否则后续的handleMessage 不会执行。
        }

        // 开始启动创建Activity 拦截，将intent还原回去。
        private void handleLaunchActivity(Message msg) {
            try {
                Object record = msg.obj; // ActivityClientRecord
                // 1.反射 从record 中拿过安检的intent
                Field intentField = record.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                Intent safeIntent = (Intent) intentField.get(record);

                // 2.从safeIntent中， 获取原来的originIntent
                Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
                // 3.还原Intent(重新设置回去intent)。
                if (originIntent != null) {
                    intentField.set(record, originIntent);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
